time_t wtm_sec, xtime_sec;
u64 tmp, usec;
+ if ((shadow_tv.tv_sec == s->wc_sec) &&
+ (shadow_tv.tv_usec == s->wc_usec))
+ return;
+
shadow_tv.tv_sec = s->wc_sec;
shadow_tv.tv_usec = s->wc_usec;
/*
* Reads a consistent set of time-base values from Xen, into a shadow data
- * area. Must be called with the xtime_lock held for writing.
+ * area.
*/
-static void __get_time_values_from_xen(void)
+static void get_time_values_from_xen(void)
{
shared_info_t *s = HYPERVISOR_shared_info;
struct vcpu_time_info *src;
while (dst->version != src->time_version1);
dst->tsc_to_usec_mul = dst->tsc_to_nsec_mul / 1000;
-
- if ((shadow_tv.tv_sec != s->wc_sec) ||
- (shadow_tv.tv_usec != s->wc_usec))
- update_wallclock();
}
static inline int time_values_up_to_date(int cpu)
unsigned long seq;
unsigned long usec, sec;
unsigned long max_ntp_tick;
- unsigned long flags;
s64 nsec;
unsigned int cpu;
struct shadow_time_info *shadow;
+ u32 local_time_version;
cpu = get_cpu();
shadow = &per_cpu(shadow_time, cpu);
do {
unsigned long lost;
+ local_time_version = shadow->version;
seq = read_seqbegin(&xtime_lock);
usec = get_usec_offset(shadow);
* overflowed). Detect that and recalculate
* with fresh values.
*/
- write_seqlock_irqsave(&xtime_lock, flags);
- __get_time_values_from_xen();
- write_sequnlock_irqrestore(&xtime_lock, flags);
+ get_time_values_from_xen();
continue;
}
- } while (read_seqretry(&xtime_lock, seq));
+ } while (read_seqretry(&xtime_lock, seq) ||
+ (local_time_version != shadow->version));
put_cpu();
again:
nsec = (s64)tv->tv_nsec - (s64)get_nsec_offset(shadow);
if (unlikely(!time_values_up_to_date(cpu))) {
- __get_time_values_from_xen();
+ get_time_values_from_xen();
goto again;
}
{
int cpu = get_cpu();
struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu);
- s64 off;
- unsigned long flags;
-
- for ( ; ; ) {
- off = get_nsec_offset(shadow);
- if (time_values_up_to_date(cpu))
- break;
- write_seqlock_irqsave(&xtime_lock, flags);
- __get_time_values_from_xen();
- write_sequnlock_irqrestore(&xtime_lock, flags);
- }
+ u64 time;
+ u32 local_time_version;
+
+ do {
+ local_time_version = shadow->version;
+ smp_rmb();
+ time = shadow->system_timestamp + get_nsec_offset(shadow);
+ if (!time_values_up_to_date(cpu))
+ get_time_values_from_xen();
+ smp_rmb();
+ } while (local_time_version != shadow->version);
put_cpu();
- return shadow->system_timestamp + off;
+ return time;
}
EXPORT_SYMBOL(monotonic_clock);
struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu);
do {
- __get_time_values_from_xen();
+ get_time_values_from_xen();
delta = delta_cpu =
shadow->system_timestamp + get_nsec_offset(shadow);
update_process_times(user_mode(regs));
profile_tick(CPU_PROFILING, regs);
}
+
+ update_wallclock();
}
/*
return;
}
#endif
- __get_time_values_from_xen();
+ get_time_values_from_xen();
+ update_wallclock();
xtime.tv_sec = shadow_tv.tv_sec;
xtime.tv_nsec = shadow_tv.tv_usec * NSEC_PER_USEC;
set_normalized_timespec(&wall_to_monotonic,
init_cpu_khz();
/* Get timebases for new environment. */
- __get_time_values_from_xen();
+ get_time_values_from_xen();
+ update_wallclock();
/* Reset our own concept of passage of system time. */
processed_system_time =